package world.criver.crc;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class CRC {
    /**
     * 加密
     * @param secret_key 密钥
     * @param text 原文
     * @return 密文
     */
    public String encrypt(String secret_key,String text){
        try {
            byte[] ts = text.getBytes(StandardCharsets.UTF_8);
//        log("a",ts);
            ts = Base64.getEncoder().encode(ts);
//        log("b",ts);
            byte[] sks = transformSecretKey(secret_key.getBytes(StandardCharsets.UTF_8));
            ts = encryptBytes(sks, ts);
//        log("c",ts);
            return new String(Base64.getEncoder().encode(ts), StandardCharsets.UTF_8);
        }catch (Exception e){
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 解密
     * @param secret_key 密钥
     * @param text 密文
     * @return 原文
     */
    public String decrypt(String secret_key,String text){
        try {
            byte[] ts = text.getBytes(StandardCharsets.UTF_8);
            ts = Base64.getDecoder().decode(ts);
//        log("d",ts);
            byte[] sks = transformSecretKey(secret_key.getBytes(StandardCharsets.UTF_8));
            ts = decryptBytes(sks, ts);
//        log("e",ts);
            ts = Base64.getDecoder().decode(ts);
//        log("f",ts);
            return new String(ts, StandardCharsets.UTF_8);
        }catch (Exception e){
            e.printStackTrace();
            return "";
        }
    }

    /**
     * byte组加密
     * @param sks
     * @param ts
     * @return
     */
    private byte[] encryptBytes(byte[] sks,byte[] ts){
        byte[] nts=new byte[ts.length];
        for(int i=0;i<ts.length;i++){
//            if(i%sks.length==0)log("oo",sks);
            nts[i]=encryptByte(sks[i%sks.length],ts[i]);
            sks[i%sks.length]=encryptByte(sks[i%sks.length],nts[i]);
        }
        return nts;
    }

    /**
     * byte组解密
     * @param sks
     * @param ts
     * @return
     */
    private byte[] decryptBytes(byte[] sks,byte[] ts){
        byte[] nts=new byte[ts.length];
        for(int i=0;i<ts.length;i++){
//            if(i%sks.length==0)log("pp",sks);
            nts[i]=decryptByte(sks[i%sks.length],ts[i]);
            sks[i%sks.length]=encryptByte(sks[i%sks.length],ts[i]);
        }
        return nts;
    }
    /**
     * 字节加密
     * @param a 密钥
     * @param b 原文
     * @return 密文
     */
    private byte encryptByte(byte a,byte b){
        byte n= (byte) (a&~'c');
        byte m= (byte) (a&'r');
        byte q= (byte) (n^m);
        byte e= (byte) (b^n);
        e=left(e,2);
        e ^= m;
        e=right(e,3);
        e^=q;
        return e;
    }

    /**
     * 字节解密
     * @param a
     * @param b
     * @return
     */
    private byte decryptByte(byte a,byte b){
        byte n= (byte) (a&~'c');
        byte m= (byte) (a&'r');
        byte q= (byte) (n^m);
        byte e= (byte) (b^q);
        e=left(e,3);
        e ^= m;
        e=right(e,2);
        e^=n;
        return e;
    }
    /**
     * 处理密钥
     * @param bs
     * @return
     */
    private byte[] transformSecretKey(byte[] bs){
        for(int i=0;i<bs.length;i++)bs[i]=transform(bs[i]);
        return bs;
    }

    /**
     * 对单个byte进行转换
     * @param b
     * @return
     */
    private byte transform(byte b){
        byte n= (byte) (b^'c');
        byte m= (byte) (b^'r');
        byte nn= (byte) (n&m);
        byte mm= (byte) (n|m);
        n= left(nn,2);
        m= right(mm,3);
        return (byte) (n^m);
    }

    /**
     * 左移
     * @param b
     * @param num
     * @return
     */
    private byte left(byte b,int num){
        String a=byteToBin(b);
        String c=a.substring(num)+a.substring(0,num);
        return (byte) Integer.parseInt(c,2);
    }

    /**
     * 右移
     * @param b
     * @param num
     * @return
     */
    private byte right(byte b,int num){
        String a=byteToBin(b);
        String c=a.substring(a.length()-num)+a.substring(0,a.length()-num);
        return (byte) Integer.parseInt(c,2);
    }
    private String byteToBin(byte b){
        String a="";
        for(int i=7;i>=0;i--)a+=((b>>i)&1)==1?"1":"0";
        return a;
    }
}
